//////////////////////////////////////////////////////////////////////
//
//	ZETeam source code 
//	Copyright (c) ZETeam 2011-..
//	
//	File: CMetaClass.h
//  Description: MetaClass definition.
// 
//	History:
//	- March 27, 2011: Created by Max Streltsov
//
//////////////////////////////////////////////////////////////////////

#ifndef __CMETACLASS_H__
#define __CMETACLASS_H__

#include <vector>

struct IFunctionHandler;
struct IScriptObject;

typedef int (*UserDataFunction)(IFunctionHandler * pH, void * callee, void * p_buffer);

class CMetaClass
{
public:

	CMetaClass(const std::string & class_name, CMetaClass * super_class):
		_class_name(class_name),
		_super_class(super_class)
	{

	}

	~CMetaClass()
	{
		
	}
	
	std::string getClassName() const
	{
		return _class_name;
	}

	CMetaClass * getSuperClass() const
	{
		return _super_class;
	}

private:

	std::string _class_name;
	CMetaClass  * _super_class;	
};

typedef std::vector<CMetaClass *> CMetaClassTable;

class CMetaClassRegistry
{
public:

	CMetaClassRegistry():
		_is_inited(false)
	{
	}

	~CMetaClassRegistry()
	{
		shutdown();
	}

	void init()
	{
		if (_is_inited)
		{
			return;
		}

		_is_inited = true;
	}

	void shutdown()
	{
		if (!_is_inited)
		{
			return;
		}

		for (unsigned int i = 0; i < _table.size(); i++)
		{
			delete _table[i];
			_table[i] = NULL;
		}


		_is_inited = false;
	}

	CMetaClass * getByName(const std::string & metaclass_name)
	{
		for (unsigned int i = 0; i < _table.size(); i++)
		{
			if (_table[i]->getClassName() == metaclass_name)
			{
				return _table[i];
			}
		}

		return NULL;
	}

	CMetaClass * registerRoot(const std::string & metaclass_name)
	{
		CMetaClass * new_class = getByName(metaclass_name);

		if (!new_class)
		{
			new_class = addNewClass(metaclass_name, NULL);
		}

		return new_class;
	}

	CMetaClass * registerMetaClass(const std::string & metaclass_name,
		                              const std::string & super_name)
	{
		CMetaClass * new_class = getByName(metaclass_name);
		CMetaClass * super_class = getByName(super_name);

		if (!new_class)
		{
			new_class = addNewClass(metaclass_name, super_class);
		}

		if (new_class->getSuperClass() != super_class)
		{
			return NULL;
		}

		return new_class;
	}

private:
	
	CMetaClass * addNewClass(const std::string & metaclass_name,
											CMetaClass * super_class)
	{
		CMetaClass * new_class = new CMetaClass(metaclass_name, super_class);
		_table.push_back(new_class);

		return new_class;
	}

	bool _is_inited;
	CMetaClassTable _table;
};

#endif // __CMETACLASS_H__